package com.server.rpcserver;


import com.common.entity.RPCRequest;
import com.common.entity.RPCResponse;
import com.common.service.UserService;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;

/**
 * @author Zixiang Hu
 * @description
 * @create 2021-03-01-14:44
 */
@AllArgsConstructor
@Slf4j
@Builder
public class NettyServerHandler extends SimpleChannelInboundHandler<RPCRequest> {
    private ServiceProvider serviceProvider;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RPCRequest msg) throws Exception {
        RPCResponse response = handleRequest(msg);
        log.info("客户端请求处理完毕，准备发往客户端的响应信息是：{}", response);
        ctx.writeAndFlush(response);
        ReferenceCountUtil.release(msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("NettyServerHandler发生异常，异常信息：{}", cause.getMessage());
        ctx.close();
    }

    /**
     * 处理客户端发送的请求并返回响应
     *
     * @param rpcRequest
     * @return
     */
    private RPCResponse handleRequest(RPCRequest rpcRequest) throws Exception {
        Object service = serviceProvider.getService(rpcRequest.getInterfaceName());
        if (service == null) {
            log.error("请求的服务不存在");
            return RPCResponse.fail();
        }
//        if (service instanceof UserService)
//            Thread.sleep(10000);
        // 通过反射调用方法获得方法执行结果
        String methodName = rpcRequest.getMethodName();
        Method method = service.getClass().getMethod(methodName, rpcRequest.getParamsTypes());
        Object res = method.invoke(service, rpcRequest.getParams());
        // 构建统一响应对象
        if (res != null) {
            RPCResponse response = RPCResponse.builder().requestId(rpcRequest.getRequestId())
                    .code(200)
                    .message("OK")
                    .dataType(res.getClass())
                    .data(res).build();
            return response;
        } else {
            return RPCResponse.success(null);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
        IdleState stat = idleStateEvent.state();
        if (stat == IdleState.READER_IDLE) {
            log.info("长时间未收到心跳包，断开连接");
            ctx.channel().close();
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
